#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rbuf.h"

int rbuf_init(char *buf, int size)
{
	int head_size = RBUF_HEAD_SIZE;
	if (size <= head_size) {
		return -1;
	}

	rbuf_t *rbuf = (rbuf_t *)buf;

	rbuf->buf = buf + head_size;
	rbuf->buf_size = size - head_size;
	rbuf->data_len = 0;
	rbuf->front = 0;
	rbuf->rear = 0;
	
	return 0;
}

void rbuf_reset(char *buf)
{
	rbuf_t *rbuf = (rbuf_t *)buf;
	rbuf->data_len = 0;
	rbuf->front = 0;
	rbuf->rear = 0;
}

int rbuf_get_size(char *buf)
{
	rbuf_t *rbuf = (rbuf_t *)buf;
	return rbuf->data_len;
}

int rbuf_get_capacity(char *buf)
{
	rbuf_t *rbuf = (rbuf_t *)buf;
	return rbuf->buf_size - 1;
}

int rbuf_push(char *buf, char *data, int len)
{
	rbuf_t *rbuf = (rbuf_t *)buf;
	rbuf->buf = buf + RBUF_HEAD_SIZE;

	int need_len = rbuf->data_len + len;
	int capacity = rbuf->buf_size - 1;
	if (capacity < need_len) {
		if (len > capacity) {
			return -1;
		}
		else {
			int reduce_num = need_len - capacity;
			rbuf->front = (rbuf->front + reduce_num) % rbuf->buf_size;
			rbuf->data_len -= reduce_num;
		}
	}

	if (rbuf->rear + len >= rbuf->buf_size) {
		int num = rbuf->buf_size - rbuf->rear;
		memcpy(rbuf->buf + rbuf->rear, data, num);
		rbuf->rear = 0;
		int left = len - num;
		if (left > 0) {
			memcpy(rbuf->buf, data + num, left);
			rbuf->rear += left;
		}
	}
	else {
		memcpy(rbuf->buf + rbuf->rear, data, len);
		rbuf->rear += len;
	}

	rbuf->data_len += len;
	return 0;
}

int rbuf_pop(char *buf, char *data, int len)
{
	rbuf_t *rbuf = (rbuf_t *)buf;
	rbuf->buf = buf + RBUF_HEAD_SIZE;
	
	if (rbuf->data_len < len) {
		return -1;
	}

	if (rbuf->front + len >= rbuf->buf_size) {
		int num = rbuf->buf_size - rbuf->front;
		memcpy(data, rbuf->buf + rbuf->front, num);
		rbuf->front = 0;

		int left = len - num;
		if (left  > 0) {
			memcpy(data + num, rbuf->buf, left);
			rbuf->front += left;
		}
	}
	else {
		memcpy(data, rbuf->buf + rbuf->front, len);
		rbuf->front += len;
	}

	rbuf->data_len -= len;
	return 0;
}
